package com.kylin.cf;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.LongPrimitiveIterator;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.EuclideanDistanceSimilarity;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

public class MahoutCf extends Base {

  private static Connection connection;

  private static final long PERIOD_DAY = 24 * 60 * 60 * 1000;

  //TODO 写入数据库

  public static void main(String[] args) throws IOException, TasteException {

    Calendar calendar = Calendar.getInstance();
    //凌晨3点
    calendar.set(Calendar.HOUR_OF_DAY, 3);
    calendar.set(Calendar.MINUTE, 0);
    calendar.set(Calendar.SECOND, 0);
    //第一次执行定时任务的时间
    Date date = calendar.getTime();
    Timer timer = new Timer();
    TimerTask timerTask = new TimerTask() {
      @Override
      public void run() {
        try {
          init();
          clear();
          itemCF();
          userCF();
          close();
          System.out.println("数据计算完成");
        } catch (IOException e) {
          e.printStackTrace();
        } catch (TasteException e) {
          e.printStackTrace();
        }

      }
    };
    //安排指定的任务在指定的时间开始进行重复的固定延迟执行。
    timer.schedule(timerTask, date, PERIOD_DAY);
  }


  public static void itemCF() throws IOException, TasteException {

    DataModel model = new FileDataModel(tmpFile, ";");
    ItemSimilarity item = new EuclideanDistanceSimilarity(model); //欧几里得
    Recommender r = new GenericItemBasedRecommender(model, item);
    LongPrimitiveIterator iter = model.getUserIDs();
    String fileName = "/Users/t1mon/IdeaProjects/febs_mahout_cf/engine/data/output/item_cf.csv";
    saveToFile(fileName, r, iter, "item");
    System.out.println("itemCF写入mysql...");
    saveToMysqlFromFile(fileName);
  }

  public static void userCF() throws TasteException, IOException {
    DataModel model = new FileDataModel(tmpFile, ";");
    UserSimilarity user = new PearsonCorrelationSimilarity(model); //皮尔森
    NearestNUserNeighborhood neighbor = new NearestNUserNeighborhood(NEIGHBORHOOD_NUM, user, model);
    Recommender r = new GenericUserBasedRecommender(model, neighbor, user);
    //得到用户ID
    LongPrimitiveIterator iter = model.getUserIDs();
    String fileName = "/Users/t1mon/IdeaProjects/febs_mahout_cf/engine/data/output/user_cf.csv";
    saveToFile(fileName, r, iter, "user");
    System.out.println("userCF写入mysql...");
    saveToMysqlFromFile(fileName);
  }

  /**
   * 直接写入文件，再手动导入数据库
   */
  private static String saveToFile(String fileName, Recommender r, LongPrimitiveIterator iter,
      String type) {
    File file = new File(fileName);
    try (BufferedWriter br = new BufferedWriter(new FileWriter(file))) {
      StringBuilder sb = new StringBuilder();
      while (iter.hasNext()) {
        long uid = iter.nextLong();
        List<RecommendedItem> list = r.recommend(uid, RECOMMENDER_NUM);
        for (RecommendedItem ritem : list) {
          //写入文件内容
          sb.append(uid).append(",")
              .append(ritem.getItemID()).append(",")
              .append(ritem.getValue()).append(",")
              .append(type).append("\n");
        }
      }
      br.write(sb.toString());
      br.flush();
      System.out.println("写入文件成功");
    } catch (IOException e) {
      e.printStackTrace();
    } catch (TasteException e) {
      e.printStackTrace();
    }
    return "";
  }

  /**
   * 测试， 实际不使用
   */
  public static void baseContent() throws TasteException, IOException {
    DataModel model = new FileDataModel(tmpFile, ";");//数据模型
    ItemSimilarity item = new PearsonCorrelationSimilarity(model);//用户相识度算法
    Recommender r = new GenericItemBasedRecommender(model, item);//物品推荐算法
    LongPrimitiveIterator iter = model.getUserIDs();
    int count = 0;
    while (count < 10 && iter.hasNext()) {
      long uid = iter.nextLong();
      List<RecommendedItem> list = r.recommend(uid, 10);
      System.out.printf("uid:%s", uid);
      for (RecommendedItem ritem : list) {
        System.out
            .printf("(book id: %s,recommend rate: %f)", thing2long.toStringID(ritem.getItemID()),
                ritem.getValue());
      }
      System.out.println();
      count++;
    }
  }

  /**
   * 获取jdbc连接， 写入数据库是要用，
   */
  protected static Connection getConnection() {
    if (connection != null) {
      return connection;
    } else {
      try {
        Class.forName("com.mysql.jdbc.Driver");
        connection = DriverManager.getConnection(
            "jdbc:mysql://115.29.140.3:3306/febs_spark_wc?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC",
            "root", "root");
        return connection;
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    return null;
  }

  /**
   *
   */
  private static void saveToMysqlFromFile(String fileName) {
    File file = new File(fileName);
    String sql = "insert into mahout_cf(uid, book_id, rate, cf_type) values(?,?,?,?)";
    PreparedStatement pstat = null;
    Connection connection = null;
    try (BufferedReader br = new BufferedReader(new FileReader(file))) {
      connection = getConnection();
      pstat = connection.prepareStatement(sql);
      String line;
      while ((line = br.readLine()) != null) {
        String[] arr = line.split(",");
        pstat.setLong(1, Long.parseLong(arr[0]));
        pstat.setString(2, arr[1]);
        pstat.setDouble(3, Double.parseDouble(arr[2]));
        pstat.setString(4, arr[3]);
        pstat.addBatch();
      }
      pstat.executeBatch();
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (SQLException e) {
      e.printStackTrace();
    } finally {
      if (pstat != null) {
        try {
          pstat.close();
        } catch (SQLException e) {
          e.printStackTrace();
        }
      }
    }
  }

  /**
   * 清空表数据
   */
  private static void clear() {
    Connection connection = getConnection();
    Statement stat = null;
    try {
      stat = connection.createStatement();
      stat.execute("truncate mahout_cf");
      System.out.println("数据清理完成");
    } catch (SQLException e) {
      e.printStackTrace();
    } finally {
      if (stat != null) {
        try {
          stat.close();
        } catch (SQLException e) {
          e.printStackTrace();
        }
      }
    }
  }

  /**
   * 关闭mysql connection
   */
  private static void close() {
    if (connection != null) {
      try {
        connection.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }
}




/*
CREATE TABLE `mahout_cf` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uid` int(11) DEFAULT NULL,
  `book_id` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  `rate` double(10,2) DEFAULT NULL,
  `cf_type` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_uid` (`uid`) USING BTREE,
  KEY `idx_book_id` (`book_id`(191)) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
 */

/*
CREATE TABLE `books` (
  `ISBN` varchar(13) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '',
  `Book-Title` varchar(255) DEFAULT NULL,
  `Book-Author` varchar(255) DEFAULT NULL,
  `Year-Of-Publication` int(10) unsigned DEFAULT NULL,
  `Publisher` varchar(255) DEFAULT NULL,
  `Image-URL-S` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `Image-URL-M` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  `Image-URL-L` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`ISBN`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 */

/*
CREATE TABLE `users` (
  `User-ID` int(11) NOT NULL DEFAULT '0',
  `Location` varchar(250) DEFAULT NULL,
  `Age` int(11) DEFAULT NULL,
  PRIMARY KEY (`User-ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 */